
package peertopeerclient;

import java.net.*;  /* The java.net package contains the basics needed for network operations. */
import java.io.*;   /* The java.io package contains the basics needed for IO operations. */
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
/* Class that manipulates files. */

public class PeerToPeerClient {
    private int mainServerPort;
    private int serverPort;
    private int readCharactere;
    private String[] fileListReceived;
    private String[] keyboardInputSplited;
    private String fileList;
    private String mainServerHost;
    private String serverHost;
    private String sentMessage;
    private String receivedMessage;
    private String keyboardInput;
    private InetAddress address;
    private Socket mainServerConnection;
    private Socket serverConnection;
    private StringBuffer receivedMessageBuffer;
    private StringBuffer fileListBuffer;
    private BufferedOutputStream bufferedOutputStream;
    private OutputStreamWriter outputStreamWriter;
    private BufferedInputStream bufferedInputStream;
    private InputStreamReader inputStreamReader;
    private FileManipulation fileManipulation;
    private Scanner scanner;
    private static Runtime runTime;
    private static Process process;
    
    public PeerToPeerClient(int mainServerPort, String mainServerHost){
        try {
            this.scanner = new Scanner(System.in);
            this.mainServerPort = mainServerPort;
            this.mainServerHost = mainServerHost;
            this.fileManipulation = new FileManipulation("opt/grupo22");
            this.fileList = "";
            
            /* Obtain an address object for the MAinServer. */
            address = InetAddress.getByName(mainServerHost);
            /* Establish a socket connection with the MainServer. */
            mainServerConnection = new Socket(address, mainServerPort);
            //System.out.println("\n Connected");
            /* Get file list. */
            this.fileListReceived = fileManipulation.returnList();
            
            for(int i = 0; i < fileListReceived.length -1; i ++){
                //System.out.println("\n File " + i + ": ");
                this.fileList = this.fileList + this.fileListReceived[i];
                this.fileList = this.fileList + "/";
                //System.out.println(this.fileList);
            }
            //if(fileListReceived.length > 1){
                this.fileList = this.fileList + this.fileListReceived[fileListReceived.length -1];
            //}
            
            /* Building Message. */
            this.sentMessage = "upList" + " " + this.fileList + (char)13;
            //this.sentMessage = "ACK" + (char)13;
            //System.out.println("\n Message seted");
            /* Send file list to MainServer. */
            do{
                //System.out.println("\n In do");
                this.bufferedOutputStream = new BufferedOutputStream(mainServerConnection.getOutputStream());
                this.outputStreamWriter = new OutputStreamWriter(this.bufferedOutputStream,"US-ASCII");
                this.outputStreamWriter.write(this.sentMessage);
                this.outputStreamWriter.flush();

                /* Receive MainServer Answer. */
                //System.out.println("\n Answer me !");
                this.receivedMessageBuffer = new StringBuffer();
                this.bufferedInputStream = new BufferedInputStream(mainServerConnection.getInputStream());
                this.inputStreamReader = new InputStreamReader(this.bufferedInputStream);
                //System.out.println("\n WTF");
                //System.out.println("\n" + this.inputStreamReader.read());
                while( (this.readCharactere = this.inputStreamReader.read())!= (char)13){
                    //System.out.println("\n" + (char)this.readCharactere);
                    receivedMessageBuffer.append((char) this.readCharactere);
                    //System.out.println("\n Receiving");
                }
                this.receivedMessage = this.receivedMessageBuffer.toString();
                //System.out.println("\n" + this.receivedMessage);
            }while(!this.receivedMessage.equals("ACK"));
            
            /* Closing connection with the MainServer */
            System.out.println("\nThread closed.");
            this.outputStreamWriter.close();
            this.bufferedOutputStream.close();
            this.inputStreamReader.close();
            this.bufferedInputStream.close();
            this.outputStreamWriter = null;
            this.bufferedOutputStream = null;
            this.inputStreamReader = null;
            this.bufferedInputStream = null;
            System.gc();
            //this.receivedMessageBuffer
            mainServerConnection.close();
            
            /* PeerToPeer Client Initialized. */
            System.out.println("SocketClient initialized");
            
            /* Handle Exceptions */  
        } catch (UnknownHostException ex) {
            Logger.getLogger(PeerToPeerClient.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(PeerToPeerClient.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public void setFileList(){
        this.fileList = "";
        this.fileListReceived = fileManipulation.returnList();
        for(int i = 0; i < fileListReceived.length -1; i ++){
            this.fileList = this.fileList + this.fileListReceived[i];
            this.fileList = this.fileList + "/" ;
        }
        
        this.fileList = this.fileList.concat(this.fileListReceived[fileListReceived.length -1]);
    }
    
    public void sendMessageMainServer(String message){
        try {
            /* Obtain an address object for the MAinServer. */
            this.address = InetAddress.getByName(mainServerHost);
            /* Establish a socket connection with the MainServer. */
            this.mainServerConnection = new Socket(address, mainServerPort);
            
            /* Send file list to MainServer. */
                this.bufferedOutputStream = new BufferedOutputStream(mainServerConnection.getOutputStream());
                this.outputStreamWriter = new OutputStreamWriter(this.bufferedOutputStream,"US-ASCII");
                //this.outputStreamWriter.write(this.sentMessage);
                this.outputStreamWriter.write(message);
                this.outputStreamWriter.flush();

                /* Receive MainServer Answer. */
                this.receivedMessageBuffer = new StringBuffer();
                this.bufferedInputStream = new BufferedInputStream(mainServerConnection.getInputStream());
                this.inputStreamReader = new InputStreamReader(this.bufferedInputStream);
                while( (this.readCharactere = this.inputStreamReader.read())!= (char)13){
                    receivedMessageBuffer.append((char) this.readCharactere);
                }
                this.receivedMessage = this.receivedMessageBuffer.toString();
                
                /* Closing connection with the MainServer */
        } catch (UnknownHostException ex) {
            //Logger.getLogger(PeerToPeerClient.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
           //Logger.getLogger(PeerToPeerClient.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public void receiveMessageMainServer(){
        //receivedMessageBuffer.delete(0, receivedMessageBuffer.length());
        try {
            while( (this.readCharactere = this.inputStreamReader.read())!= (char)13){
                        //System.out.println("\n" + (char)this.readCharactere);
                        receivedMessageBuffer.append((char) this.readCharactere);
                        //System.out.println("\n Receiving");
                    }
                    this.receivedMessage = this.receivedMessageBuffer.toString();
        } catch (IOException ex) {
            Logger.getLogger(PeerToPeerClient.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public void sendFile(String fileName){
        FileInputStream fileInputStream = null;
        this.receivedMessageBuffer = null;
        try {
            /* Send File. */
            File sentFile = new File(fileName);
            fileInputStream = new FileInputStream(sentFile);
            this.bufferedOutputStream = new BufferedOutputStream(serverConnection.getOutputStream());
            this.outputStreamWriter = new OutputStreamWriter(bufferedOutputStream);
            while((this.readCharactere = fileInputStream.read()) != -1){
                outputStreamWriter.write(this.readCharactere);
            }
            
            /* Receive Confirmation */
            this.bufferedInputStream = new BufferedInputStream(serverConnection.getInputStream());
            this.inputStreamReader = new InputStreamReader(fileInputStream);
            while((this.readCharactere = inputStreamReader.read()) != (char)13){
                receivedMessageBuffer.append((char)this.readCharactere);
            }
            receivedMessage = receivedMessageBuffer.toString();
            
        } catch (FileNotFoundException ex) {
            Logger.getLogger(PeerToPeerClient.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(PeerToPeerClient.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                fileInputStream.close();
            } catch (IOException ex) {
                Logger.getLogger(PeerToPeerClient.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
    
    public void receiveFile(String fileName){
        this.bufferedInputStream = null;
        try {
            /* Receive File. */
            File newVersion = new File(fileName);
            FileOutputStream fileOutputStream = new FileOutputStream(newVersion);
            bufferedInputStream = new BufferedInputStream(serverConnection.getInputStream());
            this.inputStreamReader = new InputStreamReader(bufferedInputStream);
            int readChareactere;
            while((readChareactere = inputStreamReader.read()) != -1){
                fileOutputStream.write(readChareactere);
            }
            
            /* Send Confirmation. */
            this.sentMessage = "ACK" + (char)13;
            this.bufferedOutputStream = new BufferedOutputStream(serverConnection.getOutputStream());
            OutputStreamWriter outputStreamWritter = new OutputStreamWriter(bufferedOutputStream);
            outputStreamWritter.write(sentMessage);
            outputStreamWritter.flush();
            
        } catch (IOException ex) {
            Logger.getLogger(PeerToPeerClient.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                bufferedInputStream.close();
            } catch (IOException ex) {
                Logger.getLogger(PeerToPeerClient.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
    
    public static void main(String[] args){
        
        /* Ask for MainServer Port and Host. */
        System.out.println("\n Start");
        PeerToPeerClient client = new PeerToPeerClient(20000, "localhost");
        
         /* Show Options to User. */
            System.out.println("Type: \n"
                    + "lsl: Local file list; \n"
                    + "ls: Global file list; \n"
                    + "dw filename: Download the file filename; \n"
                    + "gedit filename: Edit the file filename; \n"
                    + "rm filename: Remove the file filename; \n"
                    + "mk filename: Create the file filename; \n"
                    + "exit: Turn of client end exits.");
            
        while(true){
            /* Do Action*/
            client.keyboardInput = client.scanner.nextLine();
            switch(client.keyboardInput){
                case "lsl": /* It Works. */
                    client.fileManipulation.listagem();
                    break;
                case "ls": /* It Works. */
                    client.sendMessageMainServer("getListAll" + (char)13);
                    client.fileListReceived = client.receivedMessage.split("/");
                    for(int i = 0; i < client.fileListReceived.length; i++){
                        System.out.println(client.fileListReceived[i]);
                    }
                    break;
                case "exit": /* It Works. */
                    System.exit(0);
                    break;
                default:
                    client.keyboardInputSplited = client.keyboardInput.split(" ");
                    switch (client.keyboardInputSplited[0]){
                        case "rm": /* It Works. */
                            client.fileManipulation.remove(client.keyboardInputSplited[1]);
                            client.setFileList();
                            client.sentMessage = "rmFile " + client.keyboardInputSplited[1] + (char)13;
                            client.sendMessageMainServer(client.sentMessage);
                            break;
                        case "mk": /* It Works. */
                            client.fileManipulation.cria(client.keyboardInputSplited[1]);
                            client.setFileList();
                            client.sentMessage = "upList " + client.fileList + (char)13;
                            //System.out.println("\nNew List:" + client.sentMessage);
                            client.sendMessageMainServer(client.sentMessage);
                            break;
                        case "exl": /* It Works. */
                            System.out.println(client.fileManipulation.existe(client.keyboardInputSplited[1]));
                            break;
                        case "dw":
                            client.sentMessage = "getFile " + client.keyboardInputSplited[1] + (char)13;
                            client.sendMessageMainServer(client.sentMessage);
                            /* Get File. */
                            /* Open File. */
                            break;
                        case "gedit":
                            if(client.fileManipulation.existe(client.keyboardInputSplited[1])){
                                client.sentMessage = "openFile " + client.keyboardInputSplited[1] + (char)13;
                                client.sendMessageMainServer(client.sentMessage);
                                if(!client.receivedMessage.equals("ACK")){
                                    System.out.println("File edition not avaliable.");
                                    break;
                                }
                                runTime = Runtime.getRuntime();
                                try {
                                    process = runTime.exec("Notepad.exe " + client.keyboardInputSplited[1]);
                                    process.waitFor();
                                     client.sentMessage = "closeFile " + client.keyboardInputSplited[1] + (char)13;
                                     client.sendMessageMainServer(client.sentMessage);
                                    /* Update Everyone Else. */
                                } catch (        IOException | InterruptedException ex) {
                                    Logger.getLogger(PeerToPeerClient.class.getName()).log(Level.SEVERE, null, ex);
                                }
                            }
                            break;
                        case "up":
                            client.sentMessage = "getList " + client.keyboardInputSplited[1];
                            break;
                        default:
                            System.out.println("Unkown Command");
                            break;
                    }
            }
        }
        
    }
    
}
